package ch.fhnw.apsi.beans;

import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.Objects;

import javax.annotation.Nonnull;
import javax.annotation.Untainted;

import ch.fhnw.apsi.db.Id;
import ch.fhnw.apsi.db.InvalidInputException;
import ch.fhnw.apsi.password.PasswordHash;
import ch.fhnw.apsi.password.PasswortGenerator;
import ch.fhnw.apsi.templates.Secret;

/**
 * Credentials are stored in the session-object as the attribute "login".
 * 
 */
public class Credentials {
  private final String username;
  private final String passwortHash;
  private final boolean provisorilyPassword;
  private final long firmaId;

  /** Credentials from hash. */
  public Credentials(@Nonnull final String username, @Nonnull final String passwortHash,
      final boolean provisorilyPassword, final long firmaId) {
    super();
    this.username = username;
    this.passwortHash = passwortHash;
    this.provisorilyPassword = provisorilyPassword;
    this.firmaId = firmaId;
  }

  /** Credentials from plain password. The contents of <code>passwort</code> are not altered. */
  public Credentials(@Nonnull final String username, @Nonnull final char[] passwort, final boolean provisorilyPassword,
      final long firmaId) {
    super();
    this.username = username;
    try {
      this.passwortHash = PasswordHash.createHash(passwort);
    } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
      throw new RuntimeException("System can not create Hash.");
    }
    this.provisorilyPassword = provisorilyPassword;
    this.firmaId = firmaId;
  }

  /**
   * Username, so wie dieser vom System vergeben wurde.
   */
  @Nonnull
  @Untainted
  @Id
  public String getUsername() {
    return this.username;
  }

  /**
   * Gesalzener Passwort-Hash, wird vom System vergeben.
   * 
   * @see PasswordHash
   */
  @Nonnull
  @Untainted
  @Secret
  public String getPasswortHash() {
    return this.passwortHash;
  }

  @Untainted
  @Secret
  public boolean isProvisorilyPassword() {
    return this.provisorilyPassword;
  }

  public long getFirmaId() {
    return this.firmaId;
  }

  /**
   * 
   * <p>
   * Password: min. 8 Zeichen, max. 64 Zeichen; Erlaubte Zeichen: Zahlen, Gross- und Klein-Buchstaben mit Umlauten,
   * Punkten, Bindestrichen, Unterstrichen. Alles Andere ist verboten.
   * 
   * @param pw
   * @see {@link PasswortGenerator}
   */
  public static void validatePassword(final String pw) throws InvalidInputException {
    Objects.requireNonNull(pw);
    if (pw.length() < 8)
      throw new InvalidInputException("Passwort zu kurz. Mindestens 8 Zeichen werden benötigt.");
    if (pw.length() > 64)
      throw new InvalidInputException("Passwort zu lang. Höchstens 64 Zeichen sind erlaubt.");
    if (!pw.matches("[0-9A-Za-zäöüÄÖÜ.\\-_]*"))
      throw new InvalidInputException(
          "Ungültiges Passwort.\nErlaubte Zeichen: Zahlen, Gross- und Klein-Buchstaben mit Umlauten, Punkten, Bindestrichen, Unterstrichen.");
  }
}
